#include "vis_eth.h"

struct vis_dev *g_vdev = NULL;

static int vis_set_dma_mask(struct pci_dev *pdev)
{
    if(!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))){
        pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64));
    } else if(!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
        pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
    } else {
        vis_log_err("set dma mask failed\n");
        return -1;
    }
    return 0;
}

static void vis_init_cmac(u8 *base)
{






}

static int vis_map_bar(struct pci_dev *pdev, struct vis_bars *bars)
{
    if(!pdev || !bars)
        return -1;

    bars->qdma_bar_start = pci_resource_start(pdev, 0);
    bars->qdma_bar_len = pci_resource_len(pdev, 0);
    bars->qdma_bar_end = pci_resource_end(pdev, 0);
    bars->qdma_bar_flags = pci_resource_flags(pdev, 0);
    bars->qdma_bar_mmio_addr = pci_iomap(pdev, 0, bars->qdma_bar_len);
    if(!bars->qdma_bar_mmio_addr) {
        vis_log_err("qdma bar map failed\n");
        return -1;
    }

    bars->axil_bar_start = pci_resource_start(pdev, 2);
    bars->axil_bar_len = pci_resource_len(pdev, 2);
    bars->axil_bar_end = pci_resource_end(pdev, 2);
    bars->axil_bar_flags = pci_resource_flags(pdev, 2);
    bars->axil_bar_mmio_addr = pci_iomap(pdev, 2, bars->axil_bar_len);
    if(!bars->axil_bar_mmio_addr) {
        vis_log_err("axil bar map failed\n");
    }

    return 0;
}

static int vis_init_pcie_device(struct vis_dev *vdev)
{
    struct pci_dev *pdev = vdev->pdev;
    struct vis_bars *bars = &vdev->bars;
    int num_vectors, index;
    u16 irq_v;

    if(pci_request_regions(pdev, DRV_MODULE_NAME)) {
         vis_log_err("pci_request_regions failed\n");
         return -1;
    }

    if(pci_enable_device(pdev)) {
        vis_log_err("pci_enable_device failed\n");
        return -1;
    }

    pci_set_master(pdev);
    if(vis_set_dma_mask(pdev) < 0)
        return -1;

    if(vis_map_bar(pdev, bars))
        return -1;

    pci_read_config_word(pdev, pdev->msix_cap + PCI_MSIX_FLAGS, &irq_v);
    num_vectors = (irq_v & PCI_MSIX_FLAGS_QSIZE) + 1;
    vis_log_info("num_vector = %d\n", num_vector);

    vdev->msix = kzalloc((sizeof(struct msix_entry) * num_vectors), GFP_KERNEL);
    if(!vdev->msix) {
        vis_log_err("Can't allocate vdev->msix\n");
        return -1;
    }
    for(index = 0; index < num_vectors; index++) {

    }


}

static void vis_cleanup_pcie_device(struct vis_dev *vdev)
{
    struct pci_dev *pdev = vdev->pdev;
    struct vis_bars *bars = vdev->bars;

    if(bars->qdma_bar_mmio_addr) {
        pci_iounmap(pdev, bars->qdma_bar_mmio_addr);
        bars->qdma_bar_mmio_addr = NULL;
    }

    if(bars->axil_bar_mmio_addr) {
        pci_iounmap(pdev, bars->axil_bar_mmio_addr);
        bars->axil_bar_mmio_addr = NULL;
    }

    pci_release_regions(pdev);
    pci_disable_device(pdev);
    return;
}

int vis_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
    struct vis_dev *vdev;
    u32 devfn = pdev->devfn;

    vdev = vis_alloc_net_device(devfn);




}

void visroce_remove(struct pci_dev *pdev)
{
    struct vis_dev *vdev;
    u32 devfn = pdev->devfn;

    if(!pdev) {
        vis_log_info("pdev is NULL\n");
        return;
    }

    vdev = dev_get_drvdata(&pdev->dev);
    if(!vdev) {
        vis_log_info("vdev is NULL\n");
        return;
    }

    unregister_netdev(vdev->ndev);
    vis_qdma_exit(vdev);
    vis_cleanup_pcie_device(vdev);
    free_netdev(vdev->ndev);
    return;
}

static const struct pci_device_id vis_pci_ids[] = {
    {PCI_DEVICE(0x10ee, 0x903f),},
    {0,}
};

static struct pci_driver vis_pci_driver = {
    .name = "vis_en",
    .id_table = vis_pci_ids,
    .probe = vis_probe,
    .remove = vis_remove,
};

int vis_module_init(void)
{
    if(pci_register_driver(&vis_pci_driver)) {
        return -1;
    }
    return 0;
}

void vis_module_exit(void)
{
    pci_unregister_driver(&vis_pci_driver);
}
